# coding=utf-8
from math import sqrt


class recommender:
    schema_data = ['manhattan', 'minkowski', 'pearson', 'cos'];
    user = '';
    userdata = {};
    k = 5;

    def __init__(self, username, userdata):
        self.user = username;
        self.userdata = userdata;

    # 曼哈顿距离
    def manhattan(self, user1, user2):
        distance = 0;
        for key in user1:
            if key in user2:
                distance += abs(user1[key] - user2[key]);
        return distance;

    # 闵可夫斯基距离
    def minkowski(self, user1, user2, r=2):
        distance = 0;
        for key in user1:
            if key in user2:
                distance += pow(abs(user1[key] - user2[key]), r);
        return pow(distance, 1.0 / r);

    # 皮尔逊系数
    def pearson(self, user1, user2):
        sum = 0;
        total_score1 = 0;
        total_score2 = 0;
        total_score1_square = 0
        total_score2_square = 0;
        n = 0;
        for key in user1:
            if key in user2:
                sum += user1[key] * user2[key];
                total_score1 += user1[key];
                total_score2 += user2[key];
                n += 1;
                total_score1_square += pow(user1[key], 2);
                total_score2_square += pow(user2[key], 2);
        number1 = sum - total_score1 * total_score2 / n;
        number2 = sqrt(total_score2_square - pow(total_score2, 2) / n);
        number3 = sqrt(total_score1_square - pow(total_score1, 2) / n);
        if (number2 * number3) != 0:
            return number1 / (number2 * number3);
        else:
            return 0;

    # 余弦相似度
    def cos(self, user1, user2):
        module_x = 0;
        module_y = 0;
        dot_product = 0;
        for key in user1:
            if key in user2:
                # 模运算
                module_x += pow(user1[key], 2);
                module_y += pow(user2[key], 2);
                # 数量积
                dot_product += user1[key] * user2[key];
        return dot_product / (sqrt(module_x * module_y));

    # 最邻近用户计算
    '''
    user:需要计算的用户
    userdata:数据的集合
    schema:算法选择
    '''

    def approach(self, schema='manhattan'):
        data = [];
        if self.user != '' and self.userdata != '' and schema in self.schema_data:
            for key in self.userdata:
                if self.user != key:
                    # data.append();
                    # data.append((self.manhattan(userdata[username], userdata[key]), key));
                    algorithm = getattr(self, schema);
                    data.append((algorithm(self.userdata[self.user], self.userdata[key]), key));
            data.sort(reverse=True)
            return data;

        else:
            print 'error:you params is null';
            return 0;

    # 推荐的用户
    '''使用K最邻近算法为用户推荐'''

    def recommend(self, schema):
        sum = 0;
        SuggestedUserList = [];
        proportion = {};
        result = {};
        approach = self.approach(schema);
        if approach != 0:
            print approach;
            for i in range(self.k):
                # SuggestedUserList=self.userdata[approach[i][1]];
                sum += approach[i][0];
                SuggestedUserList.append(approach[i]);
            for key in SuggestedUserList:
                proportion[key[1]] = key[0] / sum;
                for score_name in self.userdata[key[1]]:
                    if score_name not in self.userdata[self.user]:
                        if score_name not in result:
                            result[score_name] = self.userdata[key[1]][score_name] * proportion[key[1]];
                        else:
                             result[score_name]=self.userdata[key[1]][score_name] * proportion[key[1]]+result[score_name];
                    else:
                        print 'Repeat:',score_name;
            print result;
